import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { addResizeListener, debounce, removeResizeListener } from '@/utils/util'
/**
 * threejs封装对象，用于进行一些初始化和公共函数的包装
 */
export class ThreeCreate {
  // 构造函数
  constructor(el) {
    this.domEl = el
    this.timer = null
    this.debResize = debounce(() => this.resize(), 200)

    this.opt = {
      width: 100,
      height: 100,
      ratio: 1,
    }

    this.calcSize()
    this.init()
    this.render()
    addResizeListener(this.domEl, this.debResize)
  }

  calcSize() {
    const { opt } = this

    let width = this.domEl?.clientWidth //窗口宽度
    let height = this.domEl?.clientHeight //窗口高度

    // 宽高比
    let ratio = width / height

    opt.width = width //窗口宽度
    opt.height = height //窗口高度
    opt.ratio = ratio //窗口高度
  }

  // 初始化
  init() {
    const { width, height, ratio } = this.opt
    // 创建场景
    this.scene = new THREE.Scene()
    // 创建相机
    this.camera = new THREE.PerspectiveCamera(75, ratio, 0.1, 1000)
    // 创建渲染器
    this.renderer = new THREE.WebGLRenderer()
    this.renderer.setSize(width, height)
    // 创建轨道控制器并开启阻尼
    this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    this.controls.enableDamping = true
    // 创建坐标轴辅助
    const axesHeaper = new THREE.AxesHelper(10)
    this.scene.add(axesHeaper)

    // 透视投影
    this.camera.position.set(10, 15, 10) //设置相机位置
    this.camera.lookAt(this.scene.position) //设置相机方向(指向的场景对象)
    this.domEl?.appendChild(this.renderer.domElement) //body元素中插入canvas对象
  }

  // 渲染函数
  render() {
    this.timer = requestAnimationFrame(() => this.render()) //请求再次执行渲染函数render
    this.controls.update()
    this.renderer.render(this.scene, this.camera) //执行渲染操作
    if (this.update) this.update()
  }

  resize() {
    if (this.timer) {
      cancelAnimationFrame(this.timer)
    }
    this.calcSize()
    const { width, height, ratio } = this.opt
    // 更新摄像头
    this.camera.aspect = ratio
    // 更新摄像机的投影矩阵
    this.camera.updateProjectionMatrix()
    // 更新渲染器
    this.renderer.setSize(width, height)
    // 更新渲染器像素比
    this.renderer.setPixelRatio(window.devicePixelRatio)
    this.render()
  }

  // 销毁
  destroy() {
    // 销毁事件
    // console.log('销毁事件,移除canvas', this.domEl)
    this.domEl.removeChild(this.domEl.children[0])
    removeResizeListener(this.domEl, this.debResize)
  }
}
